﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using System.Xml.Linq;

namespace GratisInc.Tools.FogBugz.WorkingOn
{
    public static class Extensions
    {
        /// <summary>
        /// Returns a Dictionary containing the KeyValuePairs in the specified collection.
        /// </summary>
        /// <typeparam name="TKey">The type of the Key.</typeparam>
        /// <typeparam name="TValue">The type of the Value.</typeparam>
        /// <param name="col">A collection of KeyValuePairs.</param>
        /// <returns>A dictionary consisting of the KeyValuePairs from col.</returns>
        public static Dictionary<TKey, TValue> FromKeyValuePairCollection<TKey, TValue>(this Dictionary<TKey, TValue> dict, IEnumerable<KeyValuePair<TKey, TValue>> col)
        {
            dict = new Dictionary<TKey, TValue>();
            foreach (KeyValuePair<TKey, TValue> kvp in col)
            {
                dict.Add(kvp.Key, kvp.Value);
            }
            return dict;
        }

        /// <summary>
        /// Attempts to get the descendants of the given name.
        /// </summary>
        /// <param name="doc">The XDocument to perform the operation on.</param>
        /// <param name="name">The XName of the descendants to retrieve.</param>
        /// <param name="result">A XDocumentDescendantsResult object containing
        /// the results, FogBugz API error, or exception generated by the operation.</param>
        /// <returns>A boolean value representing whether the operation was a success.</returns>
        public static Boolean TryGetDescendants(this XDocument doc, XName name, out XDocumentDescendantsResult result)
        {
            result = new XDocumentDescendantsResult();
            try
            {
                FogBugzApiError error;
                if(doc.IsFogBugzError(out error))
                {
                    result.FogBugzError = error;
                    return false;
                }
                else
                {
                    result.Descendants = doc.Descendants(name).ToList();
                    return true;
                }        
            }
            catch (Exception x)
            {
                result.Exception = x;
                return false;
            }
        }

        /// <summary>
        /// Evaluates the result of a FogBugz API call and determines if the result is an error.
        /// </summary>
        /// <param name="error">The resulting FogBugz error, if any.</param>
        /// <returns>A boolean value representing whether the FogBugz API call was an error</returns>
        public static Boolean IsFogBugzError(this XDocument doc, out FogBugzApiError error)
        {
            if (doc.Descendants("error").Count() == 1)
            {
                error = 
                    (
                    from c in doc.Descendants("error")
                    select new FogBugzApiError
                    {
                        Code = (int)c.Attribute("code"),
                        Message = c.Value
                    }
                    ).First();
                return true;
            }
            else
            {
                error = null;
                return false;
            }
        }

        /// <summary>
        /// Truncates the string to the specified length. This method attempts to
        /// find a good "stopping place", like punctuation, whitespace, etc to cut
        /// off the text.
        /// </summary>
        /// <param name="input">The string to be truncated.</param>
        /// <param name="length">The target length of the string, including a trailing ellipsis character.</param>
        public static String TruncateByLetters(this String input, Int32 length)
        {
            length -= 2;

            // If the string is null, return null.
            //
            if (input == null) return null;

            // If the string is short enough, just return it.
            //
            if (input.Length <= length) return input;

            Regex stoppingPlace = new Regex(@"[\s.,;:!-&\)]");
            Int32 truncateIndex = length;
            Int32 minLength = length / 2;
            while (!stoppingPlace.Match(input.Substring(truncateIndex, 1)).Success && truncateIndex > minLength)
            {
                truncateIndex--;
            }
            if (truncateIndex < minLength)
            {
                truncateIndex = length;
            }
            return String.Format("{0}\x2026", input.Substring(0, truncateIndex));
        }

        /// <summary>
        /// Opens the specified url in the user's browser.
        /// </summary>
        /// <param name="url">The url to open.</param>
        public static void OpenUrl(this Form form, String url)
        {
			try
			{
				Process.Start(url);
			}
			catch (Exception)
			{
				; // Firefox in some scenarios will result in a Win32Exception so ignore it.
			}
        }
    }
}
